import { isFunction } from "./utils.js";
import { observe } from "./observe/index.js";
import Watcher from "./observe/watcher.js";
import Dep from "./observe/dep.js";
// import

export function stateMixin(Vue) {
  Vue.prototype.$watch = function (key, handler, options = {}) {
    // console.log(key, handler);
    options.user = true; // 是一个用户自己写的watcher
    new Watcher(this, key, handler, options);
  };
}

export function initState(vm) {
  // 1. 状态的初始化
  const opts = vm.$options;
  // if (opts.props) {
  //   initProps();
  // }
  if (opts.data) {
    initData(vm);
  }
  if (opts.computed) {
    initComputed(vm, opts.computed);
  }
  if (opts.watch) {
    initWatch(vm, opts.watch);
  }
  // if (opts.methods) {
  //   initMethods();
  // }
}

function proxy(vm, source, key) {
  Object.defineProperty(vm, key, {
    get() {
      return vm[source][key];
    },
    set(newValue) {
      vm[source][key] = newValue;
    },
  });
}

function initData(vm) {
  // 获取data
  let data = vm.$options.data;
  // vue2中会将data中的所有数据进行数据劫持 Object.defineProperty
  // 注意data可能是函数
  // 1. 判断data是不是函数, 注意！！！！————这里需要建立data和vm的关系， 即通过定义的vm._data
  data = vm._data = isFunction(data) ? data.call(vm) : data;

  // 1.1 对数据进行代理， 目的是让用户能够通过vm.xx 访问到 vm._data.xx的数据
  for (let key in data) {
    proxy(vm, "_data", key);
  }

  // 2. 劫持数据， 进行响应式处理
  observe(data);
}

function initWatch(vm, watch) {
  for (let key in watch) {
    // console.log(key);
    // 取出其中的每一个值
    let handler = watch[key];
    // 数组形式
    if (Array.isArray(handler)) {
      for (let i = 0; i < handler.length; i++) {
        const handlerItem = handler[i];
        // console.log(handlerItem);
        createWatcher(vm, key, handlerItem);
      }
    } else {
      createWatcher(vm, key, handler);
    }
  }
}

function initComputed(vm, computed) {
  const watchers = (vm._computedWatchers = {});
  // console.log(computed);
  for (let key in computed) {
    const userDef = computed[key];
    // 可能是对象
    // 依赖的属性变化就重新取值  get
    let getter = typeof userDef == "function" ? userDef : userDef.get;
    // console.log(getter);

    // 每个计算属性， 本身就是一个watcher, 目前还没有使用
    watchers[key] = new Watcher(vm, getter, () => { }, { lazy: true }); // 默认不执行

    // 将key定义在vm上
    defineComputed(vm, key, userDef);
  }
}

function createWatcher(vm, key, handler) {
  return vm.$watch(key, handler);
}

let sharedProperty = {};
function defineComputed(vm, key, userDef) {
  if (typeof userDef == "function") {
    sharedProperty.get = userDef;
  } else {
    sharedProperty.get = createComputedGetter(key); // 高阶函数  userDef.get
    sharedProperty.set = userDef.set;
  }
  Object.defineProperty(vm, key, sharedProperty); // computed就是一个defineProperty
}

function createComputedGetter(key) {
  return function computedGetter() {
    // 取计算属性的值， 走的就是这个函数
    // 通过key 可以拿到对应的watcher， 这个watcher中包含了getter
    let watcher = this._computedWatchers[key];
    if (watcher.dirty) {
      // 根据dirty属性判断是否需要重新求值
      watcher.evaluate();
    }
    // 如果当前取完值后， Dep.target中还有值， 需要继续向上收集
    if (Dep.target) {
      // console.log(Dep.target);
      watcher.depend(); // watcher里面对应了多个dep
      // 计算属性watcher内部有两个dep： firstname， lastname
    }
    return watcher.value;
  };
}
